package com.swak.consistency.tcc.context;

import com.swak.annotation.ConsistencyScheme;
import com.swak.annotation.Propagation;
import com.swak.consistency.core.context.ConsistencyContext;
import com.swak.consistency.core.execption.ConsistencyException;
import com.swak.consistency.tcc.role.Role;
import com.swak.utils.StringUtils;

import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;

/**
 * Tcc 上下文
 * 
 * @author DELL
 */
@Getter
@Setter
@Accessors(chain = true)
public class TccContext extends ConsistencyContext {

	/**
	 * 事务ID
	 */
	private Long transId;

	/**
	 * 事务当前执行的阶段
	 */
	private Phase phase;

	/**
	 * 事务对象
	 */
	private TransLog trans;

	public TccContext() {
		this.scheme = ConsistencyScheme.TCC;
		this.propagation = Propagation.REQUIRED;
	}

	/**
	 * 事务是不是已经开启了
	 */
	@Override
	public boolean isOpenTransaction() {
		return this.transId != null;
	}

	/**
	 * 更新事务对象
	 * 
	 * @param trans
	 * @return
	 */
	public TccContext update(TransLog trans, Phase phase) {
		this.trans = trans;
		this.transId = trans.getTransId();
		this.phase = phase;
		return this;
	}

	/**
	 * 获得此次执行的事务角色
	 * 
	 * @return
	 */
	public Role getRole() {
		Role role = (com.swak.consistency.tcc.role.Role) this.getBindAttr().get("Role");
		if (role == null) {
			role = this.transRole();
			this.getBindAttr().put("Role", role);
		}
		return role;
	}

	/**
	 * 当前事务参与者的角色
	 * 
	 * @return
	 */
	private Role transRole() {
		if (this.getTransId() == null && this.getTrans() == null) {
			return Role.INITIATOR;
		} else if (this.getTransId() != null && this.getTrans() == null) {
			return Role.PROVIDER;
		} else if (this.getTransId() != null && this.getTrans() != null) {
			return Role.CONSUMER;
		}
		throw new ConsistencyException("不支持的事务状态:" + this.toString());
	}

	/**
	 * 获得唯一的事务上下文
	 * 
	 * @return
	 */
	public static TccContext get() {
		return ConsistencyContext.get(ConsistencyScheme.TCC);
	}

	/**
	 * 格式化输出
	 */
	@Override
	public String toString() {
		return StringUtils.format("事务ID[%s], 当前阶段[%s], %s.", this.transId, this.phase, this.proceeding);
	}
}
